package guicommon.controls;

import guicommon.controls.handlers.*;
import guicommon.gui.ControlMessage;
import guicommon.gui.UpdateMessage;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.util.concurrent.ConcurrentLinkedQueue;
import javax.swing.JPanel;

public abstract class Control {
    
    protected String id;

    protected Control owner;

    protected Integer xShift = 0, yShift = 10;

    protected MouseClickedEventHandler mouseClickedHandler;

    protected KeyPressedEventHandler keyPressedHandler;

    protected IdChangedEventHandler idChangedHandler;

    protected boolean isSubscribedOnUpdate = false;

    protected ConcurrentLinkedQueue updatesMassages;

    private static Integer counter = 0;
    
    public void SetSize(int width, int height) {
        Update("width", String.valueOf(width));        
        Update("height", String.valueOf(height));
        GetComponent().setSize(width, height);
    } 
    
    public void SetPoint(int x, int y) {
        Update("x", String.valueOf(x));        
        Update("y", String.valueOf(y));
        GetComponent().setLocation(x, y);
    }

    public void SetBackGround(Color backGround) {
        Update("SetBackGround", String.valueOf(backGround));
        GetComponent().setBackground(backGround);
    }

    public void SetOwner(Control owner) {
        this.owner = owner;
    }

    public void SetMouseClickedEventHandler(MouseClickedEventHandler handler) {
        this.mouseClickedHandler = handler;
        handler.SetSender(this);
    }

    public void SetKeyPressedEventHandler(KeyPressedEventHandler handler) {
        this.keyPressedHandler = handler;
        handler.SetSender(this);
    }

    public void SetIdChangedEventHandler(IdChangedEventHandler handler) {
        this.idChangedHandler = handler;
        handler.SetSender(this);
    }
    
    public Integer GetX() {
        return GetComponent().getX();
    }
    
    public Integer GetY() {
        return GetComponent().getY();
    }
    
    public Integer GetWidth() {
        return GetComponent().getWidth();
    }
    
    public Integer GetHeight() {
        return GetComponent().getHeight();
    }

    public Integer GetXShift() {
        return xShift;
    }

    public Integer GetYShift() {
        return yShift;
    }

    public Color GetBackGround() {
        return GetComponent().getBackground();
    }

    public Control GetOwner() {
        return owner;
    }

    public MouseClickedEventHandler GetOnMouseClickedHandler() {
        return mouseClickedHandler;
    }

    protected Control() {
        id = (counter++).toString();
    }

    public abstract ControlMessage ToMessage();

    protected void SetCommonFields(ControlMessage result) {
        result.SetX(GetX().toString());
        result.SetY(GetY().toString());
        result.SetWidth(GetWidth().toString());
        result.SetHeight(GetHeight().toString());
        result.SetBackGround(String.format("%d", GetComponent() != null ? GetBackGround().getRGB() : Color.LIGHT_GRAY));
        result.SetBodyField(ControlMessage.ID, id.toString());
        if (owner != null) {
            result.SetOwner(owner.GetID());
        }
    }

    public void Draw(Graphics g, JPanel board) {
        Graphics myGraphics = GetGraphics();
        Component myComponent = GetComponent();
        myComponent.paint(myGraphics);
        GetImage().flush();
        g.drawImage(GetImage(), GetX(), GetY(), board);
    }

    protected abstract Component GetComponent();

    protected Image LoadImage(String name) {
        Image result = null;
        try {
            result = Toolkit.getDefaultToolkit().createImage(getClass().getResource(String.format("./resources/%s", name)));
        } catch (Exception e) {
        } finally {
            return result;
        }
    }

    public boolean IsContainer() {
        return false;
    }

    public String GetID() {
        return id.toString();
    }

    protected BufferedImage image;

    public Graphics GetGraphics() {
        if (image == null) {
           image = new BufferedImage(GetWidth(), GetHeight(), BufferedImage.TYPE_4BYTE_ABGR);
        }           
        return image.getGraphics();
    }

    public Image GetImage() {
        return image;
    }

    public boolean Contains(int x, int y) {
        int thisX = GetX();
        int thisY = GetY();
        return x <= thisX + GetWidth() && x >= thisX && y <= thisY + GetHeight() && y >= thisY;
    }

    public void HandleEvent(EventArgs evtArgs) {
        if (evtArgs.getClass() == MouseEventArgs.class && mouseClickedHandler != null) {
            mouseClickedHandler.Invoke(evtArgs);
        }
        if (evtArgs.getClass() == KeyEventArgs.class && keyPressedHandler != null) {
            keyPressedHandler.Invoke(evtArgs);
        }
    }

    public void SubscribeOnUpdate(String id, ConcurrentLinkedQueue updatesMassages) {
        this.id = id;        
        isSubscribedOnUpdate = true;
        this.updatesMassages = updatesMassages;
        if (idChangedHandler != null) {
            idChangedHandler.Invoke(new IdEventArgs(id));
        }
    }

    protected void Update(String key, String value) {
        if (isSubscribedOnUpdate) {
            UpdateMessage update = new UpdateMessage();
            update.SetUpdatedField(id, key, value);
            updatesMassages.add(update);
        }
    }
}
